package com.local.videoplayer.utils;

import android.content.res.ColorStateList;
import android.graphics.Canvas;
import android.graphics.Color;
import android.graphics.Paint;
import android.graphics.Rect;
import android.graphics.drawable.Drawable;
import android.text.SpannableStringBuilder;
import android.text.Spanned;
import android.text.method.MovementMethod;
import android.text.style.AbsoluteSizeSpan;
import android.text.style.BackgroundColorSpan;
import android.text.style.BulletSpan;
import android.text.style.ClickableSpan;
import android.text.style.ForegroundColorSpan;
import android.text.style.ImageSpan;
import android.text.style.RelativeSizeSpan;
import android.text.style.ScaleXSpan;
import android.text.style.StrikethroughSpan;
import android.text.style.StyleSpan;
import android.text.style.SubscriptSpan;
import android.text.style.SuperscriptSpan;
import android.text.style.TextAppearanceSpan;
import android.text.style.TypefaceSpan;
import android.text.style.URLSpan;
import android.text.style.UnderlineSpan;
import android.view.View;
import android.widget.TextView;
import java.util.HashMap;
import java.util.Iterator;
import java.util.Map;
import java.util.Set;

/**
 * TextView Span
 * create by fuchaoyang 2017/5/28
 */
public class SpanBuilder {
  private final Map<Object, Integer> spans = new HashMap<>();
  private SpannableStringBuilder mSpannableBuilder;
  private CharSequence text;

  private SpanBuilder(CharSequence text) {
    this.text = text;
    this.mSpannableBuilder = new SpannableStringBuilder(text);
  }

  public static SpanBuilder span(CharSequence text) {
    return new SpanBuilder(text);
  }

  /**
   * 设置绝对大小
   */
  public SpanBuilder absoluteSize(int size) {
    return absoluteSize(size, false);
  }

  /**
   * 设置绝对大小
   */
  public SpanBuilder absoluteSize(int size, boolean dip) {
    return absoluteSize(size, dip, Spanned.SPAN_EXCLUSIVE_EXCLUSIVE);
  }

  /**
   * 设置绝对大小
   */
  public SpanBuilder absoluteSize(int size, boolean dip, int flags) {
    spans.put(new AbsoluteSizeSpan(size, dip), flags);
    return this;
  }

  /**
   * 设置相对大小
   */
  public SpanBuilder relativeSize(float proportion) {
    return relativeSize(proportion, Spanned.SPAN_EXCLUSIVE_EXCLUSIVE);
  }

  /**
   * 设置相对大小
   */
  public SpanBuilder relativeSize(float proportion, int flags) {
    spans.put(new RelativeSizeSpan(proportion), flags);
    return this;
  }

  /**
   * 设置文字颜色
   */
  public SpanBuilder color(int color) {
    return color(color, Spanned.SPAN_EXCLUSIVE_EXCLUSIVE);
  }

  /**
   * 设置文字颜色
   */
  public SpanBuilder color(int color, int flags) {
    spans.put(new ForegroundColorSpan(color), flags);
    return this;
  }

  /**
   * 设置背景
   */
  public SpanBuilder background(Drawable drawable) {
    return background(drawable, Spanned.SPAN_EXCLUSIVE_EXCLUSIVE);
  }

  /**
   * 设置背景
   */
  public SpanBuilder background(Drawable drawable, int flags) {
    return background(drawable, drawable.getIntrinsicWidth(), drawable.getIntrinsicHeight(), flags);
  }

  /**
   * 设置背景
   */
  public SpanBuilder background(Drawable drawable, final int w, final int h, int flags) {
    drawable.setBounds(0, 0, w, h);
    spans.put(new ImageSpan(drawable) {
      @Override
      public void draw(Canvas canvas, CharSequence text, int start, int end, float x, int top,
        int y, int bottom, Paint paint) {
        String sequence = text.subSequence(start, end).toString();
        Rect boundText = new Rect();
        paint.getTextBounds(sequence, 0, sequence.length(), boundText);
        Drawable b = getDrawable();
        Rect bounds = b.getBounds();

        int w = bounds.width() < boundText.width() ? boundText.width() : bounds.width();
        int h = bounds.height();

        float fontHeight = boundText.height();
        int maxHeight = (int) ((bottom - y) * 2 + fontHeight);
        if (h < fontHeight) {
          h = (int) fontHeight;
        } else {
          if (h > maxHeight) {
            h = maxHeight;
          }
        }

        b.setBounds(0, 0, w, h);

                    /*
                    paint.setColor(Color.WHITE);
                    canvas.drawRect(x + (bounds.width() - boundText.width()) / 2,
                            bottom - (bottom - y) - fontHeight,
                            (x + (bounds.width() - boundText.width()) / 2) + boundText.width(),
                            bottom - (bottom - y),
                            paint);
                    */
        canvas.save();
        int transY = top + (bottom - top - maxHeight) + (maxHeight - bounds.height()) / 2;
        canvas.translate(x, transY);
        b.draw(canvas);
        canvas.restore();
        paint.setColor(Color.BLACK);
        canvas.drawText(sequence, x + (bounds.width() - boundText.width()) / 2, y, paint);
      }
    }, flags);
    return this;
  }

  /**
   * 背景色
   */
  public SpanBuilder backgroundColor(int color) {
    return backgroundColor(color, Spanned.SPAN_EXCLUSIVE_EXCLUSIVE);
  }

  /**
   * 背景色
   */
  public SpanBuilder backgroundColor(int color, int flags) {
    spans.put(new BackgroundColorSpan(color), flags);
    return this;
  }

  /**
   * 设置链接
   */
  public SpanBuilder url(String url) {
    return url(url, Spanned.SPAN_EXCLUSIVE_EXCLUSIVE);
  }

  /**
   * 设置链接
   */
  public SpanBuilder url(String url, int flags) {
    spans.put(new URLSpan(url), flags);
    return this;
  }

  /**
   * 设置字体
   */
  public SpanBuilder typeface(String family) {
    return typeface(family, Spanned.SPAN_EXCLUSIVE_EXCLUSIVE);
  }

  /**
   * 设置字体
   */
  public SpanBuilder typeface(String family, int flags) {
    spans.put(new TypefaceSpan(family), flags);
    return this;
  }

  /**
   * 字体样式
   *
   * @param style {@link android.graphics.Typeface}
   */
  public SpanBuilder type(int style) {
    return type(style, Spanned.SPAN_EXCLUSIVE_EXCLUSIVE);
  }

  /**
   * 字体样式
   */
  public SpanBuilder type(int style, int flags) {
    spans.put(new StyleSpan(style), flags);
    return this;
  }

  /**
   * @param family
   * @param style
   * @param size
   * @param color
   * @param linkColor
   * @return
   */
  public SpanBuilder textAppearance(String family, int style, int size, ColorStateList color,
    ColorStateList linkColor) {
    return textAppearance(family, style, size, color, linkColor, Spanned.SPAN_EXCLUSIVE_EXCLUSIVE);
  }

  /**
   * @param family
   * @param style
   * @param size
   * @param color
   * @param linkColor
   * @param flags
   * @return
   */
  public SpanBuilder textAppearance(String family, int style, int size, ColorStateList color,
    ColorStateList linkColor, int flags) {
    spans.put(new TextAppearanceSpan(family, style, size, color, linkColor), flags);
    return this;
  }

  /**
   * 下划线
   */
  public SpanBuilder underline() {
    return underline(Spanned.SPAN_EXCLUSIVE_EXCLUSIVE);
  }

  /**
   * 下划线
   */
  public SpanBuilder underline(int flags) {
    spans.put(new UnderlineSpan(), flags);
    return this;
  }

  /**
   * 删除线
   */
  public SpanBuilder strikethrough() {
    return strikethrough(Spanned.SPAN_EXCLUSIVE_EXCLUSIVE);
  }

  /**
   * 删除线
   */
  public SpanBuilder strikethrough(int flags) {
    spans.put(new StrikethroughSpan(), flags);
    return this;
  }

  /**
   * 下标
   */
  public SpanBuilder subscript() {
    return subscript(Spanned.SPAN_EXCLUSIVE_EXCLUSIVE);
  }

  /**
   * 下标
   */
  public SpanBuilder subscript(int flags) {
    spans.put(new SubscriptSpan(), flags);
    return this;
  }

  /**
   * 上标
   */
  public SpanBuilder superscript() {
    return superscript(Spanned.SPAN_EXCLUSIVE_EXCLUSIVE);
  }

  /**
   * 上标
   */
  public SpanBuilder superscript(int flags) {
    spans.put(new SuperscriptSpan(), flags);
    return this;
  }

  /**
   * x缩放
   */
  public SpanBuilder scaleX(float proportion) {
    return scaleX(proportion, Spanned.SPAN_EXCLUSIVE_EXCLUSIVE);
  }

  /**
   * x缩放
   */
  public SpanBuilder scaleX(float proportion, int flags) {
    spans.put(new ScaleXSpan(proportion), flags);
    return this;
  }

  /**
   * @param gapWidth
   * @param color
   * @return
   */
  public SpanBuilder bullet(int gapWidth, int color) {
    return bullet(gapWidth, color, Spanned.SPAN_EXCLUSIVE_EXCLUSIVE);
  }

  /**
   * @param gapWidth {@link BulletSpan}
   * @hide
   */
  public SpanBuilder bullet(int gapWidth, int color, int flags) {
    spans.put(new BulletSpan(gapWidth, color), Spanned.SPAN_EXCLUSIVE_EXCLUSIVE);
    return this;
  }

  /**
   * @param drawable
   * @return
   */
  public SpanBuilder image(Drawable drawable) {
    return image(drawable, Spanned.SPAN_EXCLUSIVE_EXCLUSIVE);
  }

  /**
   * @param drawable
   * @param flags
   * @return
   */
  public SpanBuilder image(Drawable drawable, int flags) {
    return image(drawable, 0, 0, drawable.getIntrinsicWidth(), drawable.getIntrinsicHeight(),
      flags);
  }

  /**
   * @param drawable
   * @param l
   * @param t
   * @param r
   * @param b
   * @param flags
   * @return
   */
  public SpanBuilder image(Drawable drawable, int l, int t, int r, int b, int flags) {
    drawable.setBounds(l, t, r, b);
    spans.put(new ImageSpan(drawable), flags);
    return this;
  }

  /**
   * 必须调用{@link TextView#setMovementMethod(MovementMethod)}
   */
  public SpanBuilder click(OnClickListener listener) {
    return click(listener, Spanned.SPAN_EXCLUSIVE_EXCLUSIVE);
  }

  /**
   * 必须调用{@link TextView#setMovementMethod(MovementMethod)}
   * setMovementMethod(LinkMovementMethod.getInstance())
   */
  public SpanBuilder click(final OnClickListener listener, int flags) {
    spans.put(new ClickableSpan() {
      @Override public void onClick(View widget) {
        if (listener != null) {
          listener.onClick(text);
        }
      }
    }, flags);
    //SpanTextView.this.setMovementMethod(LinkMovementMethod.getInstance());
    return this;
  }

  /**
   * @param obj
   * @return
   */
  public SpanBuilder span(Object obj) {
    return span(obj, Spanned.SPAN_EXCLUSIVE_EXCLUSIVE);
  }

  /**
   * @param obj
   * @param flags
   * @return
   */
  public SpanBuilder span(Object obj, int flags) {
    spans.put(obj, flags);
    return this;
  }

  /**
   * @return
   */
  public Set<Object> spans() {
    return spans.keySet();
  }

  /**
   * @param obj
   */
  public void remove(Object obj) {
    mSpannableBuilder.removeSpan(obj);
  }

  /**
   *
   */
  public void clear() {
    Iterator<Object> iterator = spans.keySet().iterator();
    while (iterator.hasNext()) {
      iterator.next();
      iterator.remove();
    }
  }

  public SpannableStringBuilder build() {
    Iterator<Map.Entry<Object, Integer>> iterator = spans.entrySet().iterator();
    while (iterator.hasNext()) {
      Map.Entry<Object, Integer> next = iterator.next();
      mSpannableBuilder.setSpan(next.getKey(), 0, mSpannableBuilder.length(), next.getValue());
    }
    return mSpannableBuilder;
  }

  public SpanBuilder commit(TextView textView) {
    textView.append(mSpannableBuilder);
    return this;
  }

  public interface OnClickListener {
    void onClick(CharSequence text);
  }
}